#include "./Plot/Plot.h"
#include <string>
#include "../SignalConfigDialog.h"

BEGIN_EVENT_TABLE(Plot, wxPanel)
  EVT_LEFT_DOWN(Plot::OnMouseDown)
  EVT_LEFT_DCLICK(Plot::OnMouseDoubleClick)
  EVT_MOTION(Plot::OnMouseMove)
END_EVENT_TABLE()

/*\fn Plot::Plot(wxWindow* parent, s32 Width, s32 Height,int winLength):wxPanel(parent)
Create plot panel with Irrlicht GraphicEngine
\param paren Handle of the wxWidget panel;
\param Width Width of the plot;
\param Height Height of the plot;
\winLength Length of the window in seconds.*/
Plot::Plot(wxWindow* parent, s32 Width, s32 Height,int frequency, int numSample, wchar_t *xlabel, wchar_t *ylabel, int vertDivision, bool labelFlag, bool gridFlag/*, int channel*/):wxPanel(parent)
{	
	//Initialize variables
	secLength = numSample /frequency;
	SampleFreq = frequency;
	xDivision = vertDivision; 
	xLabel = xlabel;
	yLabel = ylabel;
	flagxLabel = labelFlag;
	GridFlag = gridFlag;
	height = Height;
	width = Width;
	Engine = NULL;
	handle = wx_reinterpret_cast(unsigned long, this->GetHandle());
	numSignals = 0;

	//Gray border proportional to plot size
	xBorder = 80;
	xEndBorder = 8;
	yBorder = 30;
	gWidth = width - xBorder - xEndBorder;
	gHeight = height -yBorder;

	//Create GraphicEngine
	SetSize(wxSize(Width,Height));
	Engine=new GraphicEngine(wx_reinterpret_cast(unsigned long, this->GetHandle()),width,height);

	//Inizialize variable for signal resize and filter
	lRecord = numSample;
	lGraph = width-xBorder-xEndBorder+1; //Lunghezza plot reale

	//Signal Array

	//Initialize trigger array
	trigger = new trig[lGraph];
	for (int i=0; i<lGraph; i++)
		ResetTrigger(i);

	xColorLabel = WHITE;
}

Plot::~Plot(void)
{
	delete[] trigger;
	delete Engine;
}


void Plot::DrawPlot (void)
{
	//Draw gray border
	Engine->driver->draw2DRectangle(video::SColor(255,54,70,82), core::rect<s32>(core::position2di(0,0),core::position2di(xBorder,height)),0);
	Engine->driver->draw2DRectangle(video::SColor(255,54,70,82), core::rect<s32>(core::position2di(0,height-yBorder),core::position2di(width,height)),0);
	Engine->driver->draw2DRectangle(video::SColor(255,54,70,82), core::rect<s32>(core::position2di(width-xEndBorder,0),core::position2di(width-1,height-yBorder)),0);
	Engine->driver->draw2DRectangle(video::SColor(255,255,255,255), core::rect<s32>(core::position2di(xBorder,0),core::position2di(width-xEndBorder,height-yBorder)),0);
	
	////Draw arrow
	//for (int i=xBorder-7; i<=xBorder+8; i++)
	//	driver->draw2DLine(core::position2di(xBorder,1),core::position2di(i,10),video::SColor(255,0,0,0));
	//for (int i=yBorder-7; i<=yBorder+6; i++)
	//	driver->draw2DLine(core::position2di(width-9,height-i),core::position2di(width-1,height-yBorder),video::SColor(255,0,0,0));
}

void Plot::DrawCorner(void)
{
	//Draw internal frame
	Engine->driver->draw2DLine(core::position2di(xBorder,0),core::position2di(xBorder,height-yBorder),video::SColor(255,0,0,0));
	Engine->driver->draw2DLine(core::position2di(xBorder,height-yBorder),core::position2di(width-xEndBorder,height-yBorder),video::SColor(255,0,0,0));
	Engine->driver->draw2DLine(core::position2di(width-xEndBorder,0),core::position2di(width-xEndBorder,height-yBorder),video::SColor(255,0,0,0));
	
	//Draw external corner
	Engine->driver->draw2DLine(core::position2di(0,0),core::position2di(width,0),video::SColor(255,0,0,0));
	Engine->driver->draw2DLine(core::position2di(width-1,0),core::position2di(width-1,height-1),video::SColor(255,0,0,0));
	Engine->driver->draw2DLine(core::position2di(0,height-1),core::position2di(width-1,height-1),video::SColor(255,0,0,0));
	Engine->driver->draw2DLine(core::position2di(0,0),core::position2di(0,height-1),video::SColor(255,0,0,0));
}

void Plot::DrawGrid(int Length, wchar_t *xLabel, wchar_t *yLabel, int vertDivision)
{
	float secLabel;
	wxString sLabel;

	float horGap = ((float)gWidth)/vertDivision;
	VerticalGap = floor((float)gHeight/(numSignals*4));
	secLabel = (float)secLength/vertDivision;
	yBorder = height-VerticalGap*(numSignals*4);
	gHeight = height-yBorder;
	
	//Draw grid
	if (GridFlag)
	{
		//Draw vertical grid
		for (int i=1; i<=vertDivision-1; i++)
			Engine->driver->draw2DLine(core::position2di(xBorder+i*horGap,1),core::position2di(xBorder+i*horGap,height-yBorder),video::SColor(255,160,150,150));
		//Draw Horizontal grid
		for (int i=1; i<numSignals*4; i++)
		{
			if (i%4==2)
				Engine->driver->draw2DLine(core::position2di(xBorder+1,i*VerticalGap),core::position2di(width-xEndBorder-1,i*VerticalGap),video::SColor(255,160,150,150));
			else
				Engine->draw2DDotLine(core::position2di(xBorder+1,i*VerticalGap),core::position2di(width-xEndBorder-1,i*VerticalGap),video::SColor(255,160,150,150));
			if (i%2==1)
			{
				if ((i-1)%4==0)
				{
					sLabel.Printf(wxT("%.1f"),(float)((Signals[i/4]->MaxDyn-Signals[i/4]->Dyn/4)/Signals[i/4]->Gain));
					
					Engine->numberFont->draw(sLabel,core::rect<s32>(core::position2di(xBorder-sLabel.Len()*5,i*VerticalGap-Engine->fontSize/2),
						core::position2di((xBorder-sLabel.Len()*5),i*VerticalGap-Engine->fontSize/2)),video::SColor(255,255,255,255));
				}
				else
				{
					sLabel.Printf(wxT("%.1f"),(float)((Signals[i/4]->MinDyn+Signals[i/4]->Dyn/4)/Signals[i/4]->Gain));
					Engine->numberFont->draw(sLabel,core::rect<s32>(core::position2di(xBorder-sLabel.Len()*5,i*VerticalGap-Engine->fontSize/2),
						core::position2di(xBorder-sLabel.Len()*5,i*VerticalGap-Engine->fontSize/2)),video::SColor(255,255,255,255));
				}
			}
		}
	}
	//Draw label
	if (flagxLabel)
	{
		if (Engine->labelFont)
		{
			for (int i=1; i<=vertDivision; i++)
			{
				if ((floor(i*secLabel)==i*secLabel) || (i==vertDivision))
					sLabel.Printf(wxT("%.0f"),i*secLabel);
				else
					sLabel.Printf(wxT("%.1f"),i*secLabel);
				if (i==vertDivision)
				{
					Engine->labelFont->draw(sLabel,core::rect<s32>(core::position2di((xBorder+i*horGap-(int)sLabel.Length()*9),(height-yBorder+2)),
						core::position2di((xBorder+i*horGap),(height-yBorder+70))),xColorLabel);
				}
				else
				{
					Engine->labelFont->draw(sLabel,core::rect<s32>(core::position2di((xBorder+i*horGap-(int)sLabel.Length()*4),(height-yBorder+2)),
						core::position2di((xBorder+i*horGap),(height-yBorder+70))),xColorLabel);
				}
			}
		}
	}
	if (Engine->labelFont)
	{	
		Engine->labelFont->draw(xLabel,core::rect<s32>(core::position2di((width/2),(height-20)),
					core::position2di(width,height)),xColorLabel);
	}
	if (Engine->yLabelFont)
	{
		Engine->yLabelFont->draw(yLabel,core::rect<s32>(core::position2di(15,height-yBorder),
			core::position2di(xBorder,height)),video::SColor(255,150,150,150));
	}
}

void Plot::DrawAll(void)
{
	if (Engine->device->run())
	{
		Engine->driver->beginScene(true,true,0);
		DrawPlot();
		DrawGrid(secLength,xLabel,yLabel,xDivision);
		DrawCorner();
		DrawSignal();
		Engine->driver->endScene();
	}
}

core::position2d<s32> Plot::LabelPos(int numCh)
{
	core::position2d<s32> AbsPos;
	
	AbsPos.X = 10;
	AbsPos.Y = ((numCh+1)*2-1) * VerticalGap*2-Engine->fontSize;
	return AbsPos;
}

core::position2d<s32> Plot::AbsPos4Signal(int numCh, float x, float y)
{
	core::position2d<s32> AbsPos;
	
	y= VerticalGap*2*y;
	AbsPos.Y = ((numCh+1)*2-1)*VerticalGap*2 - y;
	if(AbsPos.Y>= height-yBorder)AbsPos.Y=height-yBorder-1;
	AbsPos.X = xBorder + x; //Rimappo solo la y, x aggiungo il bordo
	return AbsPos;
}

void Plot::DrawSignal(void)
{
	int i,j;
	int gCursor,gEndCursor;
	core::position2d<s32> Begin,End;
	
	gCursor = Signals[0]->gCursor;
	gEndCursor = gCursor + 20;
	if (gEndCursor>=lGraph) gEndCursor-=lGraph;
	if(numSignals>0)
	{
		for  (j=0; j<numSignals; j++)
		{
			for (i=0; i<lGraph-1; i++)
			{
				if (((gCursor<gEndCursor) && ((i<gCursor-1) || (i>=gEndCursor))) || ((gCursor>gEndCursor) && ((i>=gEndCursor) && (i<gCursor-1))))
				{
					Begin =AbsPos4Signal(j,i,Signals[j]->data2Plot[i]);
					End = AbsPos4Signal(j,i+1,Signals[j]->data2Plot[i+1]);
					Engine->driver->draw2DLine(Begin,End,Signals[j]->Color);					
					//Engine->driver->draw2DLine(Begin,core::position2di(Begin.X,Begin.Y+1),Signals[j]->Color); //Draw points
				}	
				else
				{
					Engine->driver->draw2DLine(core::position2di(xBorder+i,0),core::position2di(xBorder+i,height-yBorder-1),video::SColor(20,255,255,0));
				}
				//Draw Trigger
				if (j==0) //Solo la prima volta 
				{
					if (trigger[i].kind != NULL)
					{
						if (height>400)
							Engine->labelFont->draw(trigger[i].value,core::rect<s32>(core::position2di(xBorder+i,height-yBorder-20),core::position2di(xBorder+i,height-yBorder-20)),trigger[i].color);
						else
							Engine->labelFont->draw(trigger[i].value,core::rect<s32>(core::position2di(xBorder+i,height-yBorder-15),core::position2di(xBorder+i,height-yBorder-15)),trigger[i].color);
						//vertical line trigger
						//Engine->driver->draw2DLine(core::position2di(xBorder+i,1),core::position2di(core::position2di(xBorder+i,height-yBorder)),trigger[i].color);	
					}
					if (((gCursor<gEndCursor) && ((i>gCursor) && (i<gEndCursor))) || ((gCursor>gEndCursor) && ((i<gEndCursor) || (i>gCursor))))
						ResetTrigger(i);
				}
			}
			//Draw Label
			if (Engine->labelFont)
			{	
				Engine->labelFont->draw(Signals[j]->Label,core::rect<s32>(LabelPos(j),LabelPos(j)),Signals[j]->ColorLabel);
			}
		}	
		
		//for (i=0; i<lGraph-1; i++)
		//{
		//		
		//}
	}
}

void Plot::SetTrigger (int kind, video::SColor color, wxString value)
{
	trigger[Signals[0]->gCursor].color = color;
	trigger[Signals[0]->gCursor].kind = kind;
	trigger[Signals[0]->gCursor].value = value;
}

void Plot::ResetTrigger(int time)
{
	trigger[time].color = WHITE;
	trigger[time].kind = NULL;
	trigger[time].value = wxT("");
}

void Plot::ResetCurves(void)
{
	memset(Signals,0,sizeof(Signals));
	numSignals = 0;
}

void Plot::AddCurve(SignalClass *signal)
{
	Signals[numSignals] = signal;
	Signals[numSignals]->ResizeTo(lGraph);
	numSignals++;
	//VerticalGap = floor((float)gHeight/(numSignals*4));
	yBorder = 43.5; //Reinizializzo valori.
	gHeight = height-30;

	VerticalGap = floor((float)gHeight/(numSignals*4));
	
}

void Plot::AddCurves(SignalClass *signals, int n)
{
	while(n>0)
	{
		AddCurve(signals++);
		n--;
	}
}

int Plot::GetTime(void)
{
	return Signals[0]->gCursor;
}

void Plot::OnMouseDown( wxMouseEvent& event )
{
	float temp;
	int index;
	wxPoint Pos = event.GetPosition();
	if(Pos.x < xBorder)
	{
		temp = Pos.y*numSignals/gHeight;
		index = floor(temp);
		if(index >= 0 && index < numSignals)
		{
			Signals[index]->Configure();		
		}
	}	
}

void Plot::OnMouseDoubleClick( wxMouseEvent& event )
{
	SignalClass Temp;
	
	SignalConfigDialog Dia(NULL);
	Dia.SetTitle(_("All Signals"));
	Dia.m_Visible->Enable(false);
	Dia.m_button31->Enable(false);
	Temp.Gain = 1;
	Temp.DetrendOn = false;
	Temp.Color = BLUE;
	Temp.lRecord = secLength*SampleFreq;
	Temp.secLength = secLength;
	Temp.frequency = SampleFreq;
	Dia.Configure(&Temp);
	for(int i=0;i<numSignals;i++)
		{
			Signals[i]->DetrendOn	=	Temp.DetrendOn;
			Signals[i]->Color		=	Temp.Color;
			Signals[i]->Gain		=	Temp.Gain;
		}
	secLength = Temp.secLength;
}

void Plot::OnMouseMove(wxMouseEvent &event)
{
	float temp;
	int index;

	wxPoint Pos = event.GetPosition();
	if ((Pos.x < xBorder) && (Pos.y<gHeight))
	{
		temp = Pos.y*numSignals/gHeight;
		index = floor(temp);
		if(index >= 0 && index < numSignals)
		{
			for (int i=0; i<numSignals; i++)
				Signals[i]->ColorLabel = WHITE;
			Signals[index]->ColorLabel = YELLOW;	
		}
	}
	else
	{
		for (int i=0; i<numSignals; i++)
			Signals[i]->ColorLabel = WHITE;
	}
}
